package gggameserver.testbed;

import gggameserver.compiler.GGSolutionData;
import gggameserver.games.connection.ProcessConnection;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.nio.charset.Charset;

import org.apache.log4j.Logger;

public class GGRemoteTestBed implements GGTestBed {
	
    private static org.apache.log4j.Logger log = Logger.getLogger(GGRemoteTestBed.class);

    public static final Charset charset = Charset.forName("UTF-8");
	
	public static final String CMD_TESTBED_CLOSE = "tb-close";

	private Socket socket;
	private InputStream in;
	private OutputStream out;
	
	public GGRemoteTestBed(Socket soc, GGSolutionData sol) throws IOException {
		this.socket = soc;
		socket.setKeepAlive(true);
		in = socket.getInputStream();
		out = socket.getOutputStream();
	}
	
	@Override
	public void close() {
		try {
			sendCommand(CMD_TESTBED_CLOSE); // TODO
			socket.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public ProcessConnection createConnection() throws IOException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getLog() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean isValid() {
		// TODO Auto-generated method stub
		return false;
	}
	
	//------------------------------
	
//	public String send(String command, String data) throws IOException {
//		return sendCommand(command); // TODO
//	}
//	

	public byte[][] sendCommand(String command) throws IOException {
		return sendCommand(command, new byte[0][0]);
	}
	
	public byte[][] sendCommand(String command, int param) throws IOException {
		byte[][] data = new byte[1][];
		data[0] = int2ba(param);
		return sendCommand(command, data);
	}
	
	public byte[][] sendCommand(String command, String param) throws IOException {
		byte[][] data = new byte[1][];
		data[0] = string2ba(param);
		return sendCommand(command, data);
	}
	
	public byte[][] sendCommand(String command, byte[][] data) throws IOException {
		out.write('C');
		send(command);
		out.write(int2ba(data.length));
		for (int i = 0; i < data.length; i++)
			send(data[i]);
		out.flush();
		return receiveData(command); // TODO
	}
	
	private byte[] string2ba(String str) {
		return str.getBytes(charset);
	}

	private byte[][] receiveData(String command) throws IOException {
		in.read(); // R
		String command_echo = ba2string(receive()); // TODO check
		int reply_cnt = receiveInt();
		byte[][] reply = new byte[reply_cnt][];
		for (int i = 0; i < reply_cnt; i++)
			reply[i] = receive();
		return reply;
	}
	
	public String ba2string(byte[] data) {
		return new String(data, charset);
	}
	
	private byte[] int2ba(int n) {
		byte[] b = new byte[4];
		for (int i = 0; i < 4; i++) b[i] = (byte)((n >> i*8) & 0xff);
		return b;
	}
	
	private int ba2int(byte[] data) {
		int n = 0;
		for (int i = 0; i < 4; i++) n |= (data[i] & 0xff) << i*8;
		return n;
	}
	
	private void send(byte[] data) throws IOException {
		out.write(int2ba(data.length));
		out.write(data);
	}

	private void send(String str) throws IOException {
		send(string2ba(str));
	}
	
	public int receiveInt() throws IOException {
		byte[] len_data = new byte[4];
		int read_len = in.read(len_data); // TODO
		int len_value = ba2int(len_data);
		return len_value;
	}
	
	private byte[] receive() throws IOException {
		int len_value = receiveInt();
		byte[] data = new byte[len_value];
		int read_len = in.read(data); // TODO
		return data;
	}

}
